<?php

declare (strict_types = 1);

namespace app\admin\model\admin;

use app\common\model\admin\Role as RoleModel;
use app\admin\model\admin\RoleMenu as RoleMenuModel;
use Exception;
use think\db\exception\DbException;

/**
 * 后台管理员用户角色模型
 * Class Role
 */
class Role extends RoleModel
{

    /**
     * 获取角色列表
     * @param array $param
     * @return array
     * @throws DbException
     */
    public function getList(array $param = []): array
    {

        $list = $this->getAll($param);
        return $this->getTreeData($list);
    }

    /**
     * 获取所有角色
     */
    private function getAll(array $param = [])
    {
        // 查询模型
        $query = $this->getNewQuery();
        // 查询参数
        $params = $this->setQueryDefaultValue($param, ['search' => '']);
        // 关键词搜索
        !empty($params['search']) && $query->where('name', 'like', "%{$params['search']}%");

        // 获取列表数据
        $list = $query->with(['roleMenu'])
            ->where('is_delete', '=', '0')
            ->order(['sort' => 'asc', 'create_time' => 'asc'])
            ->select();
        // 整理角色的菜单ID集
        return $this->getRoleMenuIds($list);
    }

    /**
     * 整理菜单的api ID集
     * @param $list
     * @return mixed
     */
    private function getRoleMenuIds($list): mixed
    {
        foreach ($list as &$item) {
            if (!empty($item['roleMenu'])) {
                $item['menus'] = getArrayColumn($item['roleMenu'], 'menu_id');
            }
        }
        return $list;
    }

    /**
     * 获取树状列表
     * @param $list
     * @param int $parentId
     * @return array
     */
    private function getTreeData(&$list, int $parentId = 0): array
    {
        $data = [];
        foreach ($list as $key => $item) {
            if ($item['pid'] == $parentId) {
                $children = $this->getTreeData($list, $item['role_id']);
                !empty($children) && $item['children'] = $children;
                $data[] = $item;
                unset($list[$key]);
            }
        }
        return $data;
    }

    /**
     * 新增记录
     * @param array $data
     * @return bool
     */
    public function add(array $data): bool
    {
        if (empty($data['menus'])) {
            $this->error = '菜单权限不能为空，请重新选择';
            return false;
        }
        $data['create_time'] = time();
        $data['update_time'] = time();
        $this->transaction(function () use ($data) {
            // 新增角色记录
            $this->save($data);
            // 新增角色菜单关系记录
            RoleMenuModel::increased((int)$this['role_id'], $data['menus']);
        });
        return true;
    }

    /**
     * 更新记录
     * @param array $data
     * @return bool
     */
    public function edit(array $data): bool
    {
        if (empty($data['menus'])) {
            $this->error = '菜单权限不能为空，请重新选择';
            return false;
        }
        // 判断上级角色是否为当前子级
        if (isset($data['pid']) && $data['pid'] > 0) {
            // 获取所有上级id集
            $parentIds = $this->getTopRoleIds($data['pid']);
            if (in_array($this['role_id'], $parentIds)) {
                $this->error = '上级角色不允许设置为当前子角色';
                return false;
            }
        }else{
            $data['pid'] = 0;
        }
        $data['update_time'] = time();
        $this->transaction(function () use ($data) {
            // 更新角色记录
            $this->allowField(['name', 'pid', 'sort','update_time'])->save($data);
            // 更新角色菜单关系记录
            RoleMenuModel::updates((int)$this['role_id'], $data['menus']);
        });
        return true;
    }

    /**
     * 获取所有上级id集
     * @param int $roleId
     * @param array|null $list
     * @return array
     */
    private function getTopRoleIds(int $roleId, array $list = null): array
    {
        static $parentIds = [];
        is_null($list) && $list = $this->getAll();
        foreach ($list as $item) {
            if ($item['role_id'] == $roleId && $item['pid'] > 0) {
                $parentIds[] = $item['pid'];
                $this->getTopRoleIds($item['pid'], $list);
            }
        }
        return $parentIds;
    }

    /**
     * 删除记录
     * @return bool
     * @throws Exception
     */
    public function remove(): bool
    {
        // 判断是否存在下级角色
        if (static::detail(['pid' => $this['role_id'],'is_delete'=>0])) {
            $this->error = '当前角色下存在子角色，不允许删除';
            return false;
        } 
        // 判断当前角色下存在用户
        if (UserRole::isExistsUserByRoleId($this['role_id'])) {
            $this->error = '当前角色下存在用户，不允许删除';
            return false;
        }
        return $this->transaction(function () {
            // 删除对应的菜单关系
            RoleMenuModel::setDeleteAll([['role_id','=',$this['role_id']]]);
            return $this->save(['is_delete' => 1]);
        });
    }

}
